#include "mongoc_const.h"
#include "mongoc_data.h"

int write_data_zlev(int cid, double timestamp, int nlon, int nlat, int nlev,
                    int nband_wdir_freq, int nband_wsp_freq, double t[nlat][nlon][nlev],
                    double pres[nlat][nlon][nlev], double q[nlat][nlon][nlev],
                    double wsp[nlat][nlon][nlev], double wpd[nlat][nlon][nlev],
                    double wdir_freq[nlat][nlon][nlev][nband_wdir_freq],
                    double wsp_freq [nlat][nlon][nlev][nband_wsp_freq ]) {
  if (cid >= nbundle) {
    return FORTRAN_MONGO_NO_ERROR;
  }
  struct MongoObjectBundle *bundle = &bundles[cid];

  bson_error_t error;
  size_t ndoc = 100000;
  bson_t **docs = malloc(ndoc * sizeof(bson_t*));
  size_t g = 0, l = 0, m = 0;
  char key[3], key2[3];

  time_t a = timestamp + 8 * 3600;
  struct tm *time = gmtime(&a);

  for (int j = 0; j < nlat; ++j) {
    for (int i = 0; i < nlon; ++i) {
      if (wsp[j][i][0] != 999900026055400882176.000000) {
        docs[m] = BCON_NEW(
          "grid_id", BCON_INT32(g),
          "time", BCON_DATE_TIME(mktime(time) * 1000)
        );
        bson_t child;
        // t
        bson_init(&child);
        bson_append_array_begin(docs[m], "t", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          BSON_APPEND_DOUBLE(&child, key, t[j][i][k]);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        // pres
        bson_init(&child);
        bson_append_array_begin(docs[m], "pres", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          BSON_APPEND_DOUBLE(&child, key, pres[j][i][k]);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        // q
        bson_init(&child);
        bson_append_array_begin(docs[m], "q", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          BSON_APPEND_DOUBLE(&child, key, q[j][i][k]);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        // wsp
        bson_init(&child);
        bson_append_array_begin(docs[m], "wsp", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          BSON_APPEND_DOUBLE(&child, key, wsp[j][i][k]);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        // wpd
        bson_init(&child);
        bson_append_array_begin(docs[m], "wpd", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          BSON_APPEND_DOUBLE(&child, key, wpd[j][i][k]);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        // wdir_freq
        bson_init(&child);
        bson_append_array_begin(docs[m], "wdir_freq", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          bson_t child2;
          bson_init(&child2);
          bson_append_array_begin(&child, key, -1, &child2);
          for (int b = 0; b < nband_wdir_freq; ++b) {
            sprintf(key2, "%d", b);
            BSON_APPEND_DOUBLE(&child2, key2, wdir_freq[j][i][k][b]);
          }
          bson_append_array_end(&child, &child2);
          bson_destroy(&child2);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        // wsp_freq
        bson_init(&child);
        bson_append_array_begin(docs[m], "wsp_freq", -1, &child);
        for (int k = 0; k < nlev; ++k) {
          sprintf(key, "%d", k);
          bson_t child2;
          bson_init(&child2);
          bson_append_array_begin(&child, key, -1, &child2);
          for (int b = 0; b < nband_wsp_freq; ++b) {
            sprintf(key2, "%d", b);
            BSON_APPEND_DOUBLE(&child2, key2, wsp_freq[j][i][k][b]);
          }
          bson_append_array_end(&child, &child2);
          bson_destroy(&child2);
        }
        bson_append_array_end(docs[m], &child);
        bson_destroy(&child);
        m++;
        if (m == ndoc) {
          printf("==> Insert %ld-%ld documents ...\n", l - ndoc + 1, l);
          if (!mongoc_collection_insert_many(bundle->col, docs, ndoc, NULL, NULL, &error)) {
            fprintf(stderr, "[Error]: Failed to insert data: %s\n", error.message);
            return EXIT_FAILURE;
          }
          for (m = 0; m < ndoc; ++m) {
            bson_destroy(docs[m]);
          }
          m = 0;
        }
        l++;
      }
      g++;
    }
  }
  ndoc = m;
  if (ndoc > 0) {
    printf("==> Insert %ld-%ld documents ...\n", l - m, l - 1);
    if (!mongoc_collection_insert_many(bundle->col, docs, ndoc, NULL, NULL, &error)) {
      fprintf(stderr, "[Error]: Failed to insert data: %s\n", error.message);
      return EXIT_FAILURE;
    }
  }
  for (m = 0; m < ndoc; ++m) {
    bson_destroy(docs[m]);
  }
  free(docs);

  return FORTRAN_MONGO_NO_ERROR;

}
